using System;
using System.ComponentModel;
using System.Data.SQLite;
using System.IO;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using Microsoft.Win32;
using ResourceBlender_Express.Properties;

namespace ResourceBlender_Express {
    /// <summary>
    /// Allows a user to specify the database mode and enter connection details.
    /// </summary>
    public partial class DatabaseSelector : UserControl {
        /// <summary>
        /// Initializes a new <see cref="DatabaseSelector"/>.
        /// </summary>
        public DatabaseSelector() {
            InitializeComponent();
        }

        /// <summary>
        /// Validates user input then returns a DialogResult of true.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        public bool ValidateSettings() {
            bool valid = true;
            if(cboDBMode.SelectedIndex == 0 || cboDBMode.SelectedIndex == 1) {
                txtDBHost.GetBindingExpression(TextBox.TextProperty).UpdateSource();
                txtDBPort.GetBindingExpression(TextBox.TextProperty).UpdateSource();
                txtDBUser.GetBindingExpression(TextBox.TextProperty).UpdateSource();
                txtDBDatabase.GetBindingExpression(TextBox.TextProperty).UpdateSource();
                txtDBPath.GetBindingExpression(TextBox.TextProperty).UpdateSource();
            }
            Window parentWindow = Window.GetWindow(this);
            Database.DatabaseType newType = (Database.DatabaseType)Enum.Parse(typeof(Database.DatabaseType), (cboDBMode.SelectedItem as ComboBoxItem).Tag.ToString());
            string dbHost = txtDBHost.Text,
                   dbUser = txtDBUser.Text, 
                   dbPass = txtDBPassword.Text,
                   dbDatabase = txtDBDatabase.Text,
                   dbTablePrefix = txtDBTablePrefix.Text,
                   dbPath = txtDBPath.Text;
            int dbPort = 0;
            if(newType == Database.DatabaseType.SQLite) {
                if(string.IsNullOrEmpty(dbPath)) {
                    DialogBox.Show(parentWindow, "A database file is required", "Error", DialogBox.DialogBoxType.OK, DialogBox.DialogBoxIcon.Error);
                    txtDBHost.Focus();
                    valid = false;
                }
            } else {
                if(string.IsNullOrEmpty(dbHost)) {
                    DialogBox.Show(parentWindow, "Database hostname must be entered", "Error", DialogBox.DialogBoxType.OK, DialogBox.DialogBoxIcon.Error);
                    txtDBHost.Focus();
                    valid = false;
                } else if(!int.TryParse(txtDBPort.Text, out dbPort)) {
                    DialogBox.Show(parentWindow, "Database port must be between 1 and 65536", "Error", DialogBox.DialogBoxType.OK, DialogBox.DialogBoxIcon.Error);
                    txtDBPort.Focus();
                    valid = false;
                } else if(string.IsNullOrEmpty(dbUser)) {
                    DialogBox.Show(parentWindow, "Database username must be entered", "Error", DialogBox.DialogBoxType.OK, DialogBox.DialogBoxIcon.Error);
                    txtDBUser.Focus();
                    valid = false;
                } else if(string.IsNullOrEmpty(dbDatabase)) {
                    DialogBox.Show(parentWindow, "Database name must be entered", "Error", DialogBox.DialogBoxType.OK, DialogBox.DialogBoxIcon.Error);
                    txtDBDatabase.Focus();
                    valid = false;
                }
            }
            if(newType == Database.DatabaseType.SQLite) {
                try {
                    FileInfo dbFile = new FileInfo(dbPath);
                    if(!dbFile.Directory.Exists) {
                        dbFile.Directory.Create();
                    }
                    if(dbFile.Exists) {
                        if(Settings.Default.FirstRun) {
                            if(DialogBox.Show(parentWindow, string.Format("The specified database file already exists. It is strongly recommended that you export the database, then overwrite it and re-import.{0}{0}Re-create the database now?", Environment.NewLine), "Database Exists", DialogBox.DialogBoxType.YesNo, DialogBox.DialogBoxIcon.Warning) == DialogBox.DialogBoxButton.Yes) {
                                SQLiteConnection.CreateFile(dbPath);
                            }
                        }
                    } else {
                        SQLiteConnection.CreateFile(dbPath);
                    }
                } catch(Exception ex) {
                    DialogBox.ShowAlert(parentWindow, string.Format("Error creating file: {0}", ex.Message), "Error");
                    valid = false;
                }
            }
            if(valid) { // looks good so far
                WinProgress dlg = new WinProgress("Checking database connection...", true);
                dlg.Owner = parentWindow;
                BackgroundWorker worker = new BackgroundWorker();
                bool canConnect = false;
                
                worker.DoWork += (s, dwe) => {
                    Database db = null;
                    try {
                        if(newType == Database.DatabaseType.SQLite) {
                            db = new Database(Database.DatabaseType.SQLite, Database.GetSQLiteConnectionString(dbPath), dbTablePrefix);
                        } else {
                            db = new Database(newType, Database.GetConnectionString(newType, dbHost, dbPort, dbUser, dbPass, dbDatabase), dbTablePrefix);
                        }
                        db.OpenConnection();
                        if(db.TablesExist()) {
                            canConnect = true;
                        } else {
                            db.CreateTables(true, true, true, true, true, true);
                            canConnect = true;
                        }
                    } catch {
                        throw;
                    } finally {
                        if(db != null && db.Connected) {
                            try {
                                db.CloseConnection();
                            } catch { }
                        }
                    }
                };
                worker.RunWorkerCompleted += (s, rwe) => {
                    dlg.Close();
                    string errorMessage = null;
                    if(rwe.Error != null) {
                        errorMessage = rwe.Error.Message;
                    } else {
                        errorMessage = string.Empty;
                    }
                    if(!canConnect && DialogBox.Show(parentWindow, string.Format("Could not connect to the database: {0}\n\nContinue Anyway?", errorMessage), "Warning", DialogBox.DialogBoxType.YesNo, DialogBox.DialogBoxIcon.Warning, DialogBox.DialogBoxButton.No) == DialogBox.DialogBoxButton.No) {
                        valid = false;
                    }
                };
                dlg.Owner = parentWindow;
                dlg.Show();
                worker.RunWorkerAsync();
                while(worker.IsBusy) {
                    Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate() { }));
                }
            }
            return valid;
        }

        /// <summary>
        /// Changes an invisible tab control to switch between server details for MySQL/SQLServer and a filename for SQLite.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Controls.SelectionChangedEventArgs"/> instance containing the event data.</param>
        private void cboDBMode_SelectionChanged(object sender, SelectionChangedEventArgs e) {
            switch(cboDBMode.SelectedIndex) {
                case 0:
                case 1:
                    tbcModeFields.SelectedIndex = 0;
                    break;
                case 2:
                    tbcModeFields.SelectedIndex = 1;
                    break;
            }
        }

        /// <summary>
        /// Adds a selection changed handler to the mode combobox, then displays the tab for the current mode.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void DatabaseSelector_Loaded(object sender, RoutedEventArgs e) {
            cboDBMode.SelectionChanged += new SelectionChangedEventHandler(cboDBMode_SelectionChanged);
            cboDBMode_SelectionChanged(cboDBMode, null);
        }

        /// <summary>
        /// Shows a dialog to select a database file.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void BrowseForDBFile(object sender, RoutedEventArgs e) {
            SaveFileDialog dlg = new SaveFileDialog();
            dlg.DefaultExt = ".db3";
            dlg.OverwritePrompt = false;
            dlg.CheckPathExists = true;
            dlg.FileName = txtDBPath.Text;
            dlg.Filter = "SQLite database files (.db3)|*.db3|All files|*.*";
            dlg.Title = "Database Path";
            if(dlg.ShowDialog() == true) {
                txtDBPath.Text = dlg.FileName;
            }
        }
    }
}
